View Javadoc
1   package edu.jiangxin.apktoolbox.reverse;
2   
3   import edu.jiangxin.apktoolbox.swing.extend.plugin.PluginPanel;
4   import edu.jiangxin.apktoolbox.swing.extend.listener.SelectDirectoryListener;
5   import edu.jiangxin.apktoolbox.swing.extend.listener.SelectFileListener;
6   import edu.jiangxin.apktoolbox.utils.Constants;
7   import edu.jiangxin.apktoolbox.utils.Utils;
8   import org.apache.commons.io.FilenameUtils;
9   
10  import javax.swing.*;
11  import javax.swing.filechooser.FileFilter;
12  import java.awt.*;
13  import java.awt.event.ActionEvent;
14  import java.awt.event.ActionListener;
15  import java.io.File;
16  import java.io.Serial;
17  
18  public class ApktoolPanel extends PluginPanel {
19      @Serial
20      private static final long serialVersionUID = 1L;
21  
22      public ApktoolPanel() throws HeadlessException {
23          super();
24      }
25  
26      @Override
27      public String getPluginFilename() {
28          return "apktool_2.12.0.jar";
29      }
30  
31      @Override
32      public void initUI() {
33          BoxLayout boxLayout = new BoxLayout(this, BoxLayout.Y_AXIS);
34          setLayout(boxLayout);
35  
36          JTabbedPane categoryTabbedPane = new JTabbedPane();
37          add(categoryTabbedPane);
38  
39          JPanel decodeCategoryPanel = new ApktoolDecodePanel();
40          JPanel rebuildCategoryPanel = new ApktoolRebuildPanel();
41  
42          categoryTabbedPane.addTab("Decode", null, decodeCategoryPanel, "Decode the APK file");
43          categoryTabbedPane.setSelectedIndex(0);
44          categoryTabbedPane.addTab("Rebuild", null, rebuildCategoryPanel, "Rebuild the APK file");
45      }
46  
47      abstract class ApktoolPanelBase extends JPanel {
48          @Serial
49          private static final long serialVersionUID = 1L;
50  
51          protected JPanel srcPanel;
52  
53          protected JPanel targetPanel;
54  
55          protected JPanel optionPanel;
56  
57          protected JPanel operationPanel;
58  
59          protected ApktoolPanelBase() throws HeadlessException {
60              super();
61              initUI();
62          }
63  
64          private void initUI() {
65              BoxLayout boxLayout = new BoxLayout(this, BoxLayout.Y_AXIS);
66              setLayout(boxLayout);
67  
68              createSrcPanel();
69              add(srcPanel);
70              add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
71  
72              createTargetPanel();
73              add(targetPanel);
74              add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
75  
76              createOptionPanel();
77              add(optionPanel);
78              add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
79  
80              createOperationPanel();
81              add(operationPanel);
82          }
83  
84          protected void createSrcPanel() {
85              srcPanel = new JPanel();
86              srcPanel.setLayout(new BoxLayout(srcPanel, BoxLayout.X_AXIS));
87          }
88  
89          protected void createTargetPanel() {
90              targetPanel = new JPanel();
91              targetPanel.setLayout(new BoxLayout(targetPanel, BoxLayout.X_AXIS));
92          }
93  
94          protected void createOptionPanel() {
95              optionPanel = new JPanel();
96              optionPanel.setLayout(new BoxLayout(optionPanel, BoxLayout.X_AXIS));
97          }
98  
99          protected void createOperationPanel() {
100             operationPanel = new JPanel();
101             operationPanel.setLayout(new BoxLayout(operationPanel, BoxLayout.X_AXIS));
102         }
103     }
104 
105     class ApktoolDecodePanel extends ApktoolPanelBase {
106         @Serial
107         private static final long serialVersionUID = 1L;
108 
109         private JTextField srcTextField;
110 
111         private JTextField targetTextField;
112 
113         private JCheckBox resourceIgnoreCheckBox;
114 
115         private JCheckBox overrideCheckBox;
116 
117         public ApktoolDecodePanel() throws HeadlessException {
118             super();
119         }
120 
121         @Override
122         public void createSrcPanel() {
123             super.createSrcPanel();
124 
125             srcTextField = new JTextField();
126             srcTextField.setText(conf.getString("apktool.decode.src.file"));
127 
128             JButton srcButton = new JButton(bundle.getString("choose.file.button"));
129             srcButton.addActionListener(new SelectFileListener("select a file", srcTextField));
130 
131             srcPanel.add(srcTextField);
132             srcPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
133             srcPanel.add(srcButton);
134         }
135 
136         @Override
137         public void createTargetPanel() {
138             super.createTargetPanel();
139 
140             targetTextField = new JTextField();
141             targetTextField.setText(conf.getString("apktool.decode.target.dir"));
142 
143             JButton targetButton = new JButton(bundle.getString("save.dir.button"));
144             targetButton.addActionListener(new SelectDirectoryListener("Save To", targetTextField));
145 
146             targetPanel.add(targetTextField);
147             targetPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
148             targetPanel.add(targetButton);
149         }
150 
151         @Override
152         public void createOptionPanel() {
153             super.createOptionPanel();
154 
155             resourceIgnoreCheckBox = new JCheckBox("Ignore res");
156             resourceIgnoreCheckBox.setSelected(false);
157             optionPanel.add(resourceIgnoreCheckBox);
158 
159             overrideCheckBox = new JCheckBox("Override");
160             overrideCheckBox.setSelected(true);
161             optionPanel.add(overrideCheckBox);
162         }
163 
164         @Override
165         public void createOperationPanel() {
166             super.createOperationPanel();
167 
168             JButton decodeButton = new JButton("Decode");
169             decodeButton.addActionListener(new ApktoolDecodePanel.DecodeButtonActionListener());
170 
171             operationPanel.add(decodeButton);
172         }
173 
174         private final class DecodeButtonActionListener implements ActionListener {
175             @Override
176             public void actionPerformed(ActionEvent e) {
177                 String srcPath = checkAndGetFileContent(srcTextField, "apktool.decode.src.file", "Source file is invalid");
178                 if (srcPath == null) {
179                     return;
180                 }
181 
182                 String targetPath = checkAndGetDirContent(targetTextField, "apktool.decode.target.dir", "Target directory is invalid");
183                 if (targetPath == null) {
184                     return;
185                 }
186 
187                 String srcBaseName = FilenameUtils.getBaseName(srcPath);
188                 StringBuilder sb = new StringBuilder();
189                 sb.append(ApktoolPanel.this.getPluginStartupCmd()).append(" d ")
190                         .append(srcPath).append(" -o ").append(targetPath).append(File.separator).append(srcBaseName);
191                 if (resourceIgnoreCheckBox.isSelected()) {
192                     sb.append(" -r");
193                 }
194                 if (overrideCheckBox.isSelected()) {
195                     sb.append(" -f");
196                 }
197                 Utils.executor(sb.toString(), true);
198             }
199         }
200     }
201 
202     class ApktoolRebuildPanel extends ApktoolPanelBase {
203         @Serial
204         private static final long serialVersionUID = 1L;
205 
206         private JTextField srcTextField;
207 
208         private JTextField targetTextField;
209 
210         private JCheckBox signAPK;
211 
212         public ApktoolRebuildPanel() throws HeadlessException {
213             super();
214         }
215 
216         @Override
217         public void createSrcPanel() {
218             super.createSrcPanel();
219 
220             srcTextField = new JTextField();
221             srcTextField.setText(conf.getString("apktool.rebuild.src.dir"));
222 
223             JButton srcButton = new JButton(bundle.getString("choose.dir.button"));
224             srcButton.addActionListener(new SelectDirectoryListener("Select Directory", srcTextField));
225 
226             srcPanel.add(srcTextField);
227             srcPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
228             srcPanel.add(srcButton);
229         }
230 
231         @Override
232         public void createTargetPanel() {
233             super.createTargetPanel();
234 
235             targetTextField = new JTextField();
236             targetTextField.setText(conf.getString("apktool.rebuild.target.file"));
237 
238             JButton targetButton = new JButton(bundle.getString("save.file.button"));
239             targetButton.addActionListener(new SelectFileListener("save to", targetTextField, new ApktoolRebuildPanel.ApkFileFilter()));
240 
241             targetPanel.add(targetTextField);
242             targetPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
243             targetPanel.add(targetButton);
244         }
245 
246         @Override
247         public void createOptionPanel() {
248             super.createOptionPanel();
249 
250             signAPK = new JCheckBox("sign APK");
251             signAPK.setSelected(false);
252             optionPanel.add(signAPK);
253         }
254 
255         @Override
256         public void createOperationPanel() {
257             super.createOperationPanel();
258 
259             JButton rebuildButton = new JButton("Rebuild");
260             rebuildButton.addActionListener(new ApktoolRebuildPanel.RebuildButtonActionListener());
261             operationPanel.add(rebuildButton);
262         }
263 
264         private final class RebuildButtonActionListener implements ActionListener {
265             @Override
266             public void actionPerformed(ActionEvent e) {
267                 String srcPath = checkAndGetDirContent(srcTextField, "apktool.rebuild.src.dir", "Source directory is invalid");
268                 if (srcPath == null) {
269                     return;
270                 }
271 
272                 String targetPath = checkAndGetNewFileContent(targetTextField, "apktool.rebuild.target.file", "Target file is invalid");
273                 if (targetPath == null) {
274                     return;
275                 }
276 
277                 StringBuilder sb = new StringBuilder();
278                 sb.append(ApktoolPanel.this.getPluginStartupCmd()).append(" b ")
279                         .append(srcPath).append(" -o ").append(targetPath);
280                 Utils.executor(sb.toString(), true);
281                 if (signAPK.isSelected()) {
282                     sb = new StringBuilder();
283                     sb.append(ApktoolPanel.this.getPluginStartupCmd())
284                             .append(" -keystore ").append(Utils.getToolsPath()).append(File.separator)
285                             .append("debug.keystore").append(" -alias androiddebugkey -pswd android ")
286                             .append(targetPath);
287                     Utils.executor(sb.toString(), true);
288                 }
289             }
290         }
291 
292         private final class ApkFileFilter extends FileFilter {
293 
294             @Override
295             public boolean accept(File f) {
296                 String nameString = f.getName();
297                 return nameString.toLowerCase().endsWith(".apk");
298             }
299 
300             @Override
301             public String getDescription() {
302                 return "*.apk";
303             }
304         }
305     }
306 }
307